home *** CD-ROM | disk | FTP | other *** search
- page 58,132
- ; file: ASYNC.ASM
- TITLE ASYNC DRIVER FOR MSDOS
- SUBTTL DESCRIPTION
- ;
- ; Loadable asyncrounous device driver for msdos.
- ; Written by: Mike Higgins
- ; Copyright (c) April 1984 by The Computer Entomologist.
- ;
- ; Permission is hearby granted to use or distribute this software
- ;without any restrictions. You may make copies for yourself or your
- ;friends. You may include it in any hardware or software product that you
- ;sell for profit.
- ;
- ; This software is distributed as is, and is not guaranteed to work
- ;on any particular hardware/software configuration. Furthermore, no
- ;liability is granted with this software: the user takes responcibility for
- ;any damage this software may do to his system.
- ;
- ; Nasy notices aside, if you have any questions about this software, you
- ;can reach me at the address below. If you impliment any new features or
- ;find (and fix!) any bugs, I would be happy to hear from you.
- ;
- ; Mike Higgins
- ; The Computer Entomologist
- ; P.O. Box 197
- ; Duncans Mills, CA 95430
- ;
- ; -Impliments FULL RS232 support for IBM PC and compatable async cards.
- ; -Includes 128-byte buffers on input and output.
- ; -Supports Xon/Xoff or hardware handshake. Hardware handshake uses
- ; DSR or CTS (to throttle output data) All handshake modes are
- ; treated separately, an can be used in combinations.
- ; -Bells can be set to echo when the input buffer overflows.
- ; -An inteligent half-duplex mode is available that echoes characters
- ; only after MSDOS has requested them. (Typed-ahead answers to
- ; questions apear AFTER the questions, not as you type them).
- ; -The 8th bit (parity) can optionally be stripped off on input
- ; and/or output.
- ; -Lower case characters can optionally be translated to upper case
- ; on input and/or output.
- ; -Control-c and control-s characters are optionally passed through
- ; the buffer on non-destructive reads so that the buffer does not
- ; defeat the break command to MSDOS when the buffer is full.
- ; -Several escape sequences are optionally scanned for on input that
- ; perform useful tasks when used as a console terminal:
- ; 1) A soft reset sequence that re-boots the system in the same way
- ; ALT-SHIFT-DEL does. (Default: control-C control-R control-B).
- ; 2) A flush input buffer sequence that removes all characters in
- ; the 128 byte typeahead buffer that have not been read by
- ; MSDOS yet (Default: control-X).
- ; 3) A re-draw the last output line sequence. (Default: control-R).
- ; 4) A delete line sequence that will delete all input back to the
- ; begening of the last line. (Default: control-U).
- ; 5) A skip output sequence turns this driver into a NUL device,
- ; (output data disapears) until the next skip-output sequence is
- ; types, or until input is requested. (Default: control-O).
- ; -The IOCTRL read and write function is used to query or change
- ; baud rates, bits/byte, parity, as well as enabling/disabling all
- ; the optional features mentioned above. This eliminates the
- ; necesity of a program that has special knowledge of the system.
- ; A program to change these features need not know the location of
- ; the driver or special words in low memory, or even the port
- ; address of the UART. Instead, all that is needed is the name of
- ; the device, and the format of an IOCTL write to this driver.
- ;
- ; ASSEMBLY INSTRUCTIONS:
- ; MASM ASYNC,ASYNC,ASYNC,NUL
- ; LINK ASYNC,ASYNC,ASYNC,NUL
- ; EXE2BIN ASYNC
- ; COPY ASYNC.BIN A: (IF NOT THERE ALREADY)
- ; ADD THE FOLLOWING LINE TO A:CONFIG.SYS:
- ; DRIVER=ASYNC.BIN
- ; RE-BOOT YOUR SYSTEM AND IT'S THERE! NOTE: THIS DRIVER
- ; DOES NOT GET ALONG AT ALL WITH BASICA OR MODE, AND POSSIBLY
- ; MANY OTHER PCDOS PROGRAMS THAT DO NOT CONFORM TO THE MSDOS
- ; STANDARDS. BASICA IN PARTICULAR MUCKS UP ALL THE ASYNC CARD
- ; INTERNAL REGESTERS, REDIRECTS THE HARDWARE VECTOR, AND IT
- ; NEVER PUTS THEM BACK THE WAY THEY WERE. IF YOU TRY TO USE
- ; THIS DRIVER AFTER BASICA HAS BEEN IN MEMORY, THE DRIVER WILL
- ; PROBABLY HANG YOUR SYSTEM.
- ;
- ; ***BUGS***
- ;
- ; If your RS232 device continually sends data to the driver, the driver
- ; will hang when your system boots. (The EPSON RX80 serial card sends
- ; ^Q's constantly and causes this). The current solution is to leave
- ; your device turned off until the system boots completely. Then turn
- ; the RS232 device on after the driver is ready for it, and everything
- ; works as expected.
- ;
- ; There are a lot of hooks in the driver for features that do not work
- ; yet. (For example, input data throttleing, output conversion of
- ; tabs to spaces). So don't expect all of these things to work just
- ; because there are comments about them or bits to set for them.
- ; Write me if you do impliment any of this stuff.
- SUBTTL DEFINITIONS
- PAGE
- ;
- ; DEVICE TYPE CODES
- DEVCHR EQU 08000h ;THIS IS A CHARACTER DEVICE
- DEVBLK EQU 0H ;THIS IS A BLOCK (DISK) DEVICE
- DEVIOC EQU 04000H ;THIS DEVICE ACCEPTS IOCTRL REQUESTS
- DEVNON EQU 02000H ;NON IBM DISK DRIVER
- DEVSPC EQU 010H ;CONSOLE ACCEPTS SPECIAL INTERUPT 29
- DEVCLK EQU 08H ;THIS IS THE CLOCK DEVICE
- DEVNUL EQU 04H ;THIS IS THE NUL DEVICE
- DEVSTO EQU 02H ;THIS IS THE CURRENT STANDARD OUTPUT DEVICE
- DEVSTI EQU 01H ;THIS IS THE STANDARD INPUT DEVICE
- ;
- ; ERROR STATUS BITS
- STSERR EQU 08000H ;GENERAL ERROR, SEE LOWER ORDER BITS FOR REASON
- STSBSY EQU 0200H ;DEVICE IS BUISY
- STSDNE EQU 0100H ;REQUEST IS COMPLETED
- ; ERROR REASON VALUES FOR LOWER ORDER BITS.
- ERRWP EQU 0 ;WRITE PROTECT ERROR
- ERRUU EQU 1 ;UNKNOWN UNIT
- ERRDNR EQU 2 ;DRIVE NOT READY
- ERRUC EQU 3 ;UNKNOWN COMMAND
- ERRCRC EQU 4 ;CYCLIC REDUNDANCY CHECK ERROR
- ERRBSL EQU 5 ;BAD DRIVE REQUEST STRUCTURE LENGTH
- ERRSL EQU 6 ;SEEK ERROR
- ERRUM EQU 7 ;UNKNOWN MEDIA
- ERRSNF EQU 8 ;SECTOR NOT FOUND
- ERRPOP EQU 9 ;PRINTER OUT OF PAPER
- ERRWF EQU 10 ;WRITE FAULT
- ERRRF EQU 11 ;READ FAULT
- ERRGF EQU 12 ;GENERAL FAILURE
- ;
- ; DEFINE THE BIT MEANINGS OF THE OUTPUT STATUS BYTE
- ;
- LINIDL EQU 0FFH ;IF ALL BITS OFF, XMITTER IS IDLE.
- LINXOF EQU 1 ;OUTPUT IS SUSPENDED BY XOFF
- LINEXP EQU 2 ;XMITTER IS BUISY, INTERUPT EXPECTED.
- LINSKP EQU 8 ;SKIP OUTPUT UNTIL NEXT SKIPO SEQUENC.
- LINDSR EQU 10H ;OUTPUT IS SUSPENDED UNTIL DSR COMES ON AGAIN
- LINCTS EQU 20H ;OUTPUT IS SUSPENDED UNTIL CTS COMES ON AGAIN
- ;
- ; BIT DEFINITIONS OF THE INPUT STATUS BYTE
- ;
- MODERR EQU 1 ;INPUT LINE ERRORS HAVE BEEN DETECTED.
- MODOVR EQU 4 ;RECEIVER BUFFER OVERFLOWED, DATA LOST.
- MODOFF EQU 2 ;DEVICE IS OFFLINE NOW.
- ;
- ; DEFINE THE BIT MEANINGS IN THE SPECIAL CHARACTERISTICS WORDS
- ;
- ; THE FIRST SPECIAL WORD CONTROLS HOW THE INPUT FROM THE UART IS TREATED
- ;
- INDTR EQU 2 ;DTR IS DATA-THROTTLE SIGNAL.
- INRTS EQU 4 ;RTS IS DATA-THROTTLE SIGNAL.
- INXON EQU 8 ;XON/XOFF IS USED TO THROTTLE INPUT DATA.
- INBEL EQU 010H ;BELLS ARE ECHOED WHEN BUFFER OVERFLOWS.
- INHDP EQU 020H ;HALF DUPLEX: INPUT CHARS ARE ECHOED.
- INCTX EQU 040H ;FLUSH INPUT BUFFER SEQUENCE RECOGNIZED.
- INCTR EQU 080H ;RE-DRAW CURRENT LINE ENABLED.
- INCTU EQU 0100H ;DELETE CURRENT LINE ENABLED.
- INCTO EQU 0200H ;SKIP OUTPUT SEQUENCE INABLED.
- INEST EQU 0400H ;ERRORS CAUSE STATUS RETURNS.
- INEPC EQU 0800H ;ERRORS TRANSLATE TO CODES WITH PARITY BIT ON.
- INSTP EQU 01000H ;STRIP PARITY BIT OFF ON INPUT
- INUPR EQU 02000H ;FORCE CHARACTERS TO UPPER CASE.
- INCTC EQU 04000H ;CONTROL-C LEAPS INPUT BUFFER ON N.D. READ.
- INRES EQU 08000H ;RESET SEQUENCE CAUSES SYSTEM RE-BOOT.
- ;
- ; THE SECOND SPECIAL WORD CONTROLS HOW THE OUTPUT TO THE UART IS TREATED
- ;
- OUTDSR EQU 2 ;DSR IS USED TO THROTTLE OUTPUT DATA.
- OUTCTS EQU 4 ;CTS IS USED TO THROTTLE OUTPUT DATA.
- OUTXON EQU 8 ;XON/XOFF IS USED TO THROTTLE OUTPUT DATA.
- OUTCSF EQU 010H ;CTS IS OFFLINE SIGNAL.
- OUTCDF EQU 020H ;CARRIER DETECT IS OFFLINE SIGNAL
- OUTDRF EQU 040H ;DSR IS OFFLINE SIGNAL.
- OUTSTP EQU 01000H ;STRIP PARITY OFF ON OUTPUT.
- OUTUPR EQU 02000H ;LOWER CASE XLATES TO UPPER ON OUTPUT.
- OUTTAB EQU 04000H ;TABS ARE TRANSLATED TO SPACES ON OUTPUT.
- ;
- ; DEFINE THE PORT OFFSETS AND IMPORTANT ASYNC BOARD CONSTANTS
- DLAB EQU 080H ;DIVISOR LATCH ACCESS BIT
- ALLINT EQU 01111B ;ENABLE ALL INTERUPTS IN INTEN REGESTER.
- TXBUF EQU 0 ;OFFSET TO TRANSMITTER BUFFER REGESTER
- RXBUF EQU 0 ;DITO FOR RECEIVER (DIRECTION DIFERENTIATES FUNCS)
- BAUD0 EQU 0 ;BAUD DIVISOR REG (DLAB IN LCTRL DIFFERENCIATES)
- BAUD1 EQU 1 ;BAUD DIVISOR HIGH BYTE
- INTEN EQU 1 ;INTERUPT ENABLE REGESTER
- INTID EQU 2 ;INTERUPT IDENTIFICATION REGESTER.
- LCTRL EQU 3 ;LINE CONTROL REGESTER
- MCTRL EQU 4 ;MODEM CONTROL REGESTER
- LSTAT EQU 5 ;LINE STATUS REGESTER
- MSTAT EQU 6 ;MODEM STATUS REGESTER
-
-
- BOOTS SEGMENT AT 0FFFFH ;SEGMENT FOR FAR JUMP TO WARM BOOT
- RE_BOOT LABEL FAR ;ADDRESS. THIS IS USED BY THE
- BOOTS ENDS ;RE-BOOT ESCAPE SEQUENCE, IF ENABLED.
-
- VECS SEGMENT AT 0 ;ON AN IBM PC, YOU CAN REQUEST A "QUICK" BOOT
- ORG 72H ;BY STORING 1234H IN LOCATION 0:72. THIS IS
- FLAG LABEL WORD ;THE MOST IBM SPECIFIC THING IN THIS WHOLE
- VECS ENDS ;DRIVER, YOU MAY HAVE TO CHANGE THE RE-BOOT
- ;LOGIC FOR OTHER SYSTEMS. ON THE OTHER HAND,
- ;WRITING TO 0:72 BEFORE RESETTING THE 8088
- ;CAN'T DO ANY HARM, SO YOU CAN LEAVE THIS IN.
- SUBTTL DRIVER LIST HEAD
- PAGE
- ;*************************************************************************
- ;
- ; BEGENING OF DRIVER CODE.
- ;
- DRIVER SEGMENT
- ASSUME CS:DRIVER,DS:DRIVER,ES:DRIVER
- ; ORG 0 ;DRIVERS START AT 0
- ASYNC2:
- DW ASYNC1,-1 ;POINTER TO NEXT DEVICE: DOS FILLS THIS IN.
- DW DEVCHR OR DEVIOC ;CHARACTER DEVICE
- DW STRATEGY ;OFFSET TO STRATEGY ROUTINE.
- DW REQUEST2 ;OFFSET TO "INTERUPT" ENTRYPOINT.
- DB "ASYNC2 " ;DEVICE NAME.
- ASYNC1:
- DW -1,-1 ;POINTER TO NEXT DEVICE: END OF LINKED LIST.
- DW DEVCHR OR DEVIOC ;THIS DEVICE IS CHARACTER IOCTL
- DW STRATEGY ;STRATEGY ROUTINE
- DW REQUEST1 ;I/O REQUEST ROUTINT
- DB "ASYNC1 "
- debug dd 0b8000000h
- onotify macro char
- push es
- push di
- push ax
- mov ax,'&char'
- les di,CS:debug
- stos byte ptr [di]
- inc di
- mov word ptr CS:debug,di
- pop ax
- pop di
- pop es
- endm
- SUBTTL DRIVER INTERNAL DATA STRUCTURES
- PAGE
- ;
- ASY_UNITS EQU 2 ;NUMBER OF UNITS THIS DRIVER IS BUILT FOR
-
- UNIT STRUC ;EACH UNIT HAS A STRUCTURE DEFINING IT'S STATE:
- PORT DW ? ;I/O PORT ADDRESS
- VECT DW ? ;INTERUPT VECTOR OFFSET (NOT INTERUPT NUMBER!)
- ISRADR DW ? ;OFFSET TO INTERUPT SERVICE ROUTINE
- LINE DB ? ;DEFAULT LINE CONTROL BIT SETTINGS DURING INIT,
- ;OUTPUT STATUS BITS AFTERWORDS.
- MODEM DB ? ;MODEM CONTROL BIT SETTINGS DURING INIT,
- ;INPUT STATUS BITS AFTERWARDS.
- INSPEC DW ? ;SPECIAL CHAR INPUT TREATMENT, HANDSHAKING MODE.
- OUTSPEC DW ? ;SPECIAL MODE BITS FOR OUTPUT
- BAUD DW ? ;CURRENT BAUD RATE DIVISOR VALUE
- FLSHP DW ? ;OFFSET INTO FLUSH BUFFER COMMAND STRING.
- REDRP DW ? ;OFFSET INTO RE-DRAW LINE COMMAND STRING.
- BACKP DW ? ;OFFSET INTO DELETE CURRENT LINE COMMAND STRING.
- SKIPP DW ? ;OFFSET INTO SKIP OUTPUT SEQUENCE.
- REBTP DW ? ;OFFSET INTO RE-BOOT SYSTEM COMMAND STRING.
- IFIRST DW ? ;OFFSET TO FIRST CHARACTER IN INPUT BUFFER.
- IAVAIL DW ? ;OFFSET TO NEXT AVAILABLE BYTE.
- IBUF DW ? ;POINTER TO 128 BYTE INPUT BUFFER.
- OFIRST DW ? ;OFFSET INTO FIRST CHARACTER IN OUTPUT BUFFER
- OAVAIL DW ? ;OFFSET INTO NEXT AVAIL BYTE IN OUTPUT BUFFER
- OBUF DW ? ;POINTER TO 128 BYTE OUTPUT BUFFER
- UNIT ENDS
-
- ;TABLE OF STRUCTURES FOR EACH ASYNCROUNOUS UNIT
- ;ASYNC1 DEFAULTS TO THE COM1 PORT AND VECTOR,
- ;NO PARITY, 8 DATA BITS, 1 STOP BIT,AND 9600 BAUD.
- ASY_TAB1:
- UNIT <3F8H,30H,ASY1ISR,3,0BH,0D3D0H,8,12,0,0,0,0,0,0,0,IN1BUF,0,0,OUT1BUF>
-
- ;ASYNC2 DEFAULTS TO THE COM2 PORT AND VECTOR,
- ;NO PARITY, 8 DATA BITS, 1 STOP BIT,
- ;AND 9600 BAUD.
- ASY_TAB2:
- UNIT <2F8H,2CH,ASY2ISR,3,0BH,0D3D0H,8,12,0,0,0,0,0,0,0,IN2BUF,0,0,OUT2BUF>
-
- ;IF THE BUFFER SIZE IS A POWER OF TWO, THE PROCESS OF KEEPING
- ;THE OFSETTS WITHIN THE BOUNDS OF THE BUFFER IS GREATLY
- ;SIMPLIFIED. IF YOU MODIFY THE BUFFER SIZE, KEEP IT A
- ;POWER OF 2, AND MODIFY THE MASK ACCORDINGLY.
- BUFSIZ EQU 128 ;INPUT BUFFER SIZE
- BUFMSK EQU 127 ;MASK FOR CALCULATING OFFSETS MODULO BUFSIZ
- IN1BUF DB BUFSIZ DUP (?)
- IN2BUF DB BUFSIZ DUP (?)
- OUT1BUF DB BUFSIZ DUP (?)
- OUT2BUF DB BUFSIZ DUP (?)
- ;
- ; BAUD RATE CONVERSION TABLE
- ASY_BAUDT DW 50,2304 ;FIRST VALUE IS DESIRED BAUD RATE,
- DW 75,1536 ;SECOND IS DIVISOR REGISTER VALUE.
- DW 110,1047
- DW 134,857
- DW 150,786
- DW 300,384
- DW 600,192
- DW 1200,96
- DW 1800,64
- DW 2000,58
- DW 2400,48
- DW 3600,32
- DW 4800,24
- DW 7200,16
- DW 9600,12
- ;
- ; DEFINE THE SEQUENCES OF CHARACTERS THAT ARE SCANNED FOR ON
- ; INPUT, USED TO FLUSH BUFFER, RE-BOOT, RE-DRAW LINES, ETC.
- ; EACH OF THESE SEQUENCES IS A STRING OF THREE OR LESS
- ; BYTES TERMINATED WITH A NUL. HERE THEY ARE PADDED WITH NULS
- ; TO 4 BYTES EACH SO THAT ALTERNATE SEQUENCES CAN BE PATCHED IN
- ; WITH DEBUG.
- ;
- FLUSH DB 'X' AND 1FH,0,0,0 ;FLUSH INPUT BUFFER
- REDRAW DB 'R' AND 1FH,0,0,0 ;RE-DRAW LAST LINE
- BACKL DB 'U' AND 1FH,0,0,0 ;DELETE LAST LINE
- SKIPO DB 'O' AND 1FH,0,0,0 ;SKIP OUTPUT
- REBOOT DB 'C' AND 1FH,'R' AND 1FH,'B' AND 1FH,0 ;RE-BOOT SYSTEM
-
- ;
- ; STRUCTURE OF AN I/O REQUEST PACKET STATIC HEADER
- ;
- PACK STRUC
- LEN DB ? ;LENGTH OF RECORD
- PRTNO DB ? ;UNIT CODE
- CODE DB ? ;COMMAND CODE
- STAT DW ? ;RETURN STATUS
- DOSQ DD ? ;UNUSED DOS QUE LINK POINTER
- DEVQ DD ? ;UNUSED DRIVER QUE LINK POINTER
- MEDIA DB ? ;MEDIA CODE ON READ/WRITE
- XFER DW ? ;XFER ADDRESS OFFSET
- XSEG DW ? ;XFER ADDRESS SEGMENT
- COUNT DW ? ;TRANSFER BYTE COUNT.
- PACK ENDS
- ;
- ; THE FOLLOWING TWO WORDS IS THE STORAGE AREA FOR THE REQUEST PACKET
- ; ADDRESS, SENT TO ME BY A STRATEGY ROUTINE CALL.
- ; AS REQUESTED BY THE MSDOS DRIVER MANUAL, I AM "THINKING
- ; ABOUT" THE FUTURE, SO I`M DESIGNATING THIS POINTER AS THE QUEUE
- ; LIST HEAD FOR REQUESTS TO THIS DRIVER.
- ;
- PACKHEAD DD 0
- ;
- ; THE STRATEGY ROUTINE ITSELF.
- STRATEGY PROC FAR
- ;SQUIRREL AWAY THE POINTER FOR LATER.
- MOV WORD PTR CS:PACKHEAD,BX ;STORE THE OFFSET,
- MOV WORD PTR CS:PACKHEAD+2,ES ;AND THE SEGMENT.
- RET
- STRATEGY ENDP
- SUBTTL REQUEST ROUTINES
- PAGE
- ; PHYLOSOPHICAL RUMINATIONS:
- ; Why does MicroSoft INSIST on choosing names for things that
- ; already have firmly defined meanings for OTHER things? Take for
- ; example, the MASM definition of a SEGMENT: It bears little relation
- ; to the deffinition of a segment in the intel 8088 processor handbook.
- ; This leads to a GREAT DEAL of confusion. Many other assemblers on
- ; other systems have constructs that are equivalent to MASM's SEGMENT,
- ; they are often called PSECTS for Program SECTionS. Perhaps the
- ; people at Microsoft wanted a word that made more sence in English,
- ; but I wish they had chosen SECTION instead of SEGMENT.
- ; The example that it bringing all this to mind now is the
- ; MicroSoft device driver documentation, which insists on calling
- ; the following routine an "interupt routine". Go read the intel
- ; manual, you will find that an interupt routine is defined THERE as
- ; a bunch of code that is jumped to by a special kind of event in
- ; the hardware. That is NOT what the people at MicroSquishy mean
- ; this time either. Depending on weather you describe these routines
- ; in terms of what they do now, or in the "future", the following
- ; routine should be called the "I/O request routine" or the "I/O
- ; completion routine". But NO, they had to deside to call this
- ; the "interupt routine", and create another layer of confusion for
- ; those of us who already know the traditional deffinition of this
- ; relatively well known phrase.
- ;
- ; I am herby refering to the "interupt routine" as the
- ; "request routine", and nameing all my labels accordingly.
- ;
- ; I/O REQUEST ROUTINES
- REQUEST1: ;ASYNC1 HAS BEEN REQUESTED
- PUSH SI ;SAVE SI SO YOU CAN
- MOV SI,OFFSET ASY_TAB1 ;GET THE DEVICE UNIT TABLE ADDRESS.
- JMP GEN_REQUEST ;THE GENERIC DRIVER DOES THE REST.
- REQUEST2: ;ASYNC2 HAS BEEN REQUESTED TO DO SOMETHING
- PUSH SI ;SAVE SI
- MOV SI,OFFSET ASY_TAB2 ;GET UNIT TABLE TWO`S ADDRESS
-
- GEN_REQUEST:
- PUSHF ;I REQUIRE DIRECTION FLAG CLEARED, SO I SAVE
- CLD ;THE FLAGS AND CLEAR THEM HERE.
- PUSH AX ;SAVE ALL THE REGESTERS, YOU MAY NOT
- PUSH BX ;NEED THEM ALL, BUT YOU WILL REGRET IT
- PUSH CX ;IF YOU FORGET TO SAVE JUST ONE OF THEM.
- PUSH DX
- PUSH DI
- PUSH BP
- PUSH DS
- PUSH ES
- PUSH CS ;COPY THE CS REGESTER
- POP DS ;INTO THE DS TO ACCESS MY DATA
- LES BX,PACKHEAD ;RECOVER THE POINTER TO THE PACKET.
- MOV DI,OFFSET ASY_FUNCS ;GET THE POINTER TO THE DISPATCH TABLE
- MOV AL,ES:CODE[BX] ;GET THE FUNCTION REQUEST CODE,
- MOV AH,0 ;MAKE IT INTO A WORD,
- SAL AX,1 ;CONVERT TO A WORD OFFSET,
- ADD DI,AX ;AND ADD TO THE TABLE START ADDRESS
- JMP [DI] ;JUMP TO THE APPROPRIATE ROUTINE
- ;
- ; TABLE OF OFFSETS TO ALL THE DRIVER FUNCTIONS
- ASY_FUNCS:
- DW ASYNC_INIT ;INITIALIZE DRIVER
- DW EXIT ;MEDIA CHECK (BLOCK DEVICES ONLY)
- DW EXIT ;BUILD BPB (BLOCK DEVICES ONLY)
- DW IOCTLIN ;IOCTL INPUT
- DW READ ;READ
- DW NDREAD ;NON-DESTRUCTIVE READ
- DW RXSTAT ;INPUT STATUS
- DW INFLUSH ;FLUSH INPUT BUFFER
- DW WRITE ;WRITE
- DW WRITE ;WRITE WITH VERIFY
- DW TXSTAT ;OUTPUT STATUS
- DW TXFLUSH ;FLUSH OUTPUT BUFFER
- DW IOCTLOUT ;IOCTL OUTPUT
- ;
- ; EXIT FROM DRIVER REQUEST
- ; CALL WITH AX= RETURN STATUS VALUE
- EXITP PROC FAR
- EXIT:
- LES BX,PACKHEAD ;RETREIVE POINTER TO PACKET
- OR AX,STSDNE ;SET THE DONE BIT IN IT.
- MOV ES:STAT[BX],AX ;STORE THE STATUS BACK IN THE PACKET.
-
- POP ES ;RESTORE ALL THE REGESTERS
- POP DS
- POP BP
- POP DI
- POP DX
- POP CX
- POP BX
- POP AX
- POPF
- POP SI
- RET
- EXITP ENDP
- SUBTTL READ DATA REQUEST ROUTINE
- PAGE
- ;
- ; ALL THE FOLLOWING ROUTINES ARE CALLED WITH THE SAME CONTEXT
- ; FROM THE REQUEST ROUTINE:
- ; - ES:BX POINTS TO THE I/O PACKET.
- ; ROUTINES CAN MUCK UP THESE TWO REGESTERS IF THEY WANT, AS EXIT
- ; WILL RESTORE THEM BEFORE IT TRIES TO SEND THE STATUS WORD BACK.
- ; - CS: AND DS: POINT TO THE BEGENING OF THE DRIVER SEGMENT.
- ; - DS:SI POINTS TO THE DEVICE UNIT TABLE DESCRIBING THE PARTICULAR
- ; PORT BEING ACCESSED.
- ; - ALL OTHER REGESTERS ARE AVAILABLE FOR USE, THE EXIT ROUTINE
- ; RESTORES THEM ALL BEFORE RETURNING TO MSDOS.
- ; ALL THE FOLLOWING ROUTINES SHOULD EXIT BY DOING A JMP
- ; TO THE EXIT ROUTINE. EXIT ASSUMES THAT AX
- ; CONTAINS EITHER ZERO, OR THE ERROR BIT SET AND A VALID ERROR
- ; RETURN VALUE IN THE LOW ORDER BITS. EXIT SETS THE DONE BIT IN
- ; THIS VALUE FOR YOU BEFORE IT RETURNS TO MSDOS.
- ;
- SUBTTL READ REQUEST ROUTINE
- ; READ DATA FROM DEVICE
- ;
- READ:
- MOV CX,ES:COUNT[BX] ;GET THE REQUESTED NUMBER OF BYTES
- MOV DI,ES:XFER[BX] ;DI IS OFFSET TO USER BUFFER
- MOV DX,ES:XSEG[BX] ;SEGMENT IS LAST I NEED FROM PACKET,
- MOV ES,DX ;NOW ES:DI POINTS TO USER BUFFER.
-
- TEST LINE[SI],LINSKP ;IF THERE IS A SKIP OUTPUT IN
- JE NO_SKIP ;PROGRESS, I MUST CANCEL IT NOW.
- AND LINE[SI],NOT LINSKP ;CLEAR THE SKIP OUTPUT BIT.
- CALL START_OUTPUT ;START THE XMITTER GOING AGAIN.
- NO_SKIP:
- TEST MODEM[SI],MODERR OR MODOVR ;HAVE ANY LINE ERRORS OCCURED?
- JE NO_LERR ;NOT LATELY.
- AND MODEM[SI],NOT ( MODERR OR MODOVR ) ;YES, CLEAR THE BITS,
- MOV AX,ERRRF ;AND RETURN ERROR INDICATION TO DOS
- JMP EXIT
- NO_LERR:
-
- RLUP:
- CALL GET_IN ;GET NEXT CHAR FROM INPUT BUFFER
- CMP AH,0 ;WAS THERE ONE?
- JE TEST_READ ;YES, TEST FOR SPECIAL BITS
- JMP RLUP ;NO, WAIT FOR A CHAR TO ARRIVE.
- TEST_READ:
- ;BEFORE RETURNING A CHARACTER TO MSDOS, I CHECK FOR ANY
- ;SPECIAL PROCESSING I AM REQUIRED TO DO. I DO AS MANY
- ;OF THESE FUNCTIONS HERE AS POSSIBLE, TO SAVE THE
- ;RECEIVER INTERUPT ROUTINE FROM HAVING TO DO THEM, AND
- ;TO ALLOW INTELIGENT USE OF THE RING BUFFER. FOR EXAMPLE,
- ;CHARACTERS TO NOT ECHO-HALF-DUPLEX UNTIL THEY ARE READ
- ;FROM THE BUFFER HERE, SO A PROGRAM THAT DISABLES ECHO
- ;WHILE READING A PASSWORD WILL WORK EVEN IF THE USER TYPED
- ;THE PASWORD IN BEFORE BEING PROMPTED FOR IT.
- ;************************************
- ;TEST FOR STRIPPING PARITY BIT
- TEST INSPEC[SI],INSTP ;SHOULD I STRIP PARITY?
- JE NO_STRIP ;NOPE.
- AND AL,NOT 080H ;YES.
- NO_STRIP:
- ;*********************************
- ;TEST FOR UPPER-CASE CONVERSION
- TEST INSPEC[SI],INUPR ;IS LOWER TO UPPER CONV. ENABLED?
- JE NO_UPPER ;NOPE, SKIP THIS.
- MOV AH,AL ;MAKE A COPY IN AH,
- AND AH,07FH ;STRIP PARITY TO MAKE TEST VALID,
- CMP AH,'a' ;IS IT < A LOWER CASE a?
- JL NO_UPPER ;YES, THEN IT'S NOT LOWER.
- CMP AH,'z' ;IS IT > A LOWER CASE z?
- JG NO_UPPER ;YES, THEN IT'S STILL NOT LOWER.
- SUB AL,020H ;NO, THEN CONVERT THE ONE IN AL.
- NO_UPPER:
- ;**********************************8
- ;TEST FOR HALF-DUPLEX MODE
- STOS BYTE PTR [DI] ;BUT FIRST STORE CHAR IN USER BUFFER.
- TEST INSPEC[SI],INHDP ;AM I IN HALF DUPLEX MODE?
- JE NO_HALF ;NO.
- HALF_WAIT:
- CALL PUT_OUT ;YES, PUT THE CHARACTER IN OUTBUF.
- CMP AH,0 ;WAS THERE ROOM?
- JNE HALF_WAIT ;NO, WAIT FOR IT.
- CALL START_OUTPUT ;AND MAKE SURE THE XMITTER STARTS
- NO_HALF:
- ;ALTHOUGH MSDOS NEVER, TO MY KNOWLEDGE, ASKS FOR MORE THAN
- ;ONE STUPID CHARACTER AT A TIME, I LOOP ON THE REQUEST SIZE
- ;SO THAT THIS DRIVER WILL STILL WORK ON THAT GLORIOUS DAY
- ;WHEN SOMEBODY ASKS FOR MORE THAN ONE.
- LOOP RLUP ;KEEP GOING IF YOU WERE REQUESTED.
- MOV AL,0 ;RETURN NO ERRORS IN AX IF DONE.
- JMP EXIT
- SUBTTL NON-DESTRUCTIVE READ REQUEST ROUTINE
- PAGE
- ; NON-DESTRUCTIVE READ FROM DEVICE
- ;
- NDREAD:
- MOV DI,IFIRST[SI] ;GET POINTER TO FIRST CHAR
- CMP DI,IAVAIL[SI] ;IS THE BUFFER EMPTY?
- JNE NDGET ;NO, GET ONE NON DESTRUCTIVELY.
- MOV AX,STSBSY ;YES, RETURN DEVICE BUISY
- JMP EXIT
- NDGET:
- PUSH BX ;SAVE AN EXTRA COPY OF BX.
- MOV BX,IBUF[SI] ;GET BUFFER ADDRESS
- TEST INSPEC[SI],INCTC ;SHOULD I CHECK FOR IMBEDDED ^C'S?
- JE NONDCTC ;NO.
- ;YES, SCAN BUFFER FOR CONTROL-C.
- CTCLUP:
- CMP BYTE PTR [BX+DI],'C' AND 1FH ;IS THIS A CONTROL-C?
- JNE NXTCTC ;NO, GO TRY AGAIN
- YESCTC:
- MOV IFIRST[SI],DI ;YES, DESTRUCTIVELY READ TO HERE,
- JMP NONDCTC ;AND RETURN THE CONTROL-C.
- NXTCTC:
- CMP BYTE PTR [BX+DI],'S' AND 1FH ;DO THE SAME TEST FOR ^S
- JE YESCTC ;IN CASE XON/XOFF IS DISABLED.
- INC DI ;INCRIMENT THE POINTER,
- AND DI,BUFMSK ;MODULO BUFSIZ,
- CMP DI,IAVAIL[SI] ;STOP IF YOU BUMP INTO YOURSELF,
- JNE CTCLUP ;ELSE KEEP LOOKING.
- MOV DI,IFIRST[SI] ;IF NO, CONTROL-C, RETURN FIRST CHAR
- NONDCTC:
- MOV AL,[BX+DI] ;GET THE CHARACTER,
- POP BX ;RECOVER BX AGAIN.
- MOV ES:MEDIA[BX],AL ;RETURN IT IN THE REQUEST PACKET.
- MOV AX,0 ;RETURN NO ERRORS IN AX.
- JMP EXIT
- SUBTTL INPUT STATUS REQUEST ROUTINE
- PAGE
- ; INPUT STATUS REQUEST
- ;
- RXSTAT:
- MOV DI,IFIRST[SI] ;GET POINTER TO FIRST CHAR
- CMP DI,IAVAIL[SI] ;IS THE BUFFER EMPTY?
- JNE RXFUL
- MOV AX,STSBSY ;NO, RETURN STATUS BUISY.
- JMP EXIT
- RXFUL:
- MOV AX,0 ;YES, RETURN STATUS ZERO.
- JMP EXIT
- SUBTTL INPUT FLUSH REQUEST ROUTINE
- ; INPUT FLUSH REQUEST
- ;
- INFLUSH:
- MOV AX,IAVAIL[SI] ;GET THE POINTER TO THE NEXT EMPTY
- MOV IFIRST[SI],AX ;CHAR AND POINT THE FIRST AT IT.
- MOV AX,0 ;AND RETURN DONE.
- JMP EXIT
- SUBTTL WRITE REQUEST ROUTINE
- PAGE
- ; OUTPUT DATA TO DEVICE
- ;
- WRITE:
- MOV CX,ES:COUNT[BX] ;GET BYTE COUNT,
- MOV DI,ES:XFER[BX] ;GET XFER ADDRESS OFFSET,
- MOV AX,ES:XSEG[BX] ;GET XFER SEGMENT.
- MOV ES,AX ;STORE IN ES NOW.
- TEST LINE[SI],LINSKP ;SHOULD I BE SKIPPING OUTPUT?
- JNE WRSUCC
- WLUP:
- MOV AL,ES:[DI] ;GET THE NEXT CHAR,
- INC DI ;AND INC DI PAST IT.
- ;
- ; CHECK FOR STRIP PARITY ON OUTPUT.
- ;
- TEST OUTSPEC[SI],OUTSTP ;IS THIS ENABLED?
- JE NOOSTP ;NOPE
- AND AL,NOT 080H ;YES, WACK OFF BIT SEVEN!
- NOOSTP:
- ;
- ; CHECK FOR LOWER-TO-UPPER CONVERSION ON OUTPUT
- ;
- TEST OUTSPEC[SI],OUTUPR ;IS THIS ENABLED?
- JE NOOUPR ;NOPE
- MOV AH,AL ;DO COMPARISON IN AH
- AND AH,NOT 080H ;SO YOU CAN STRIP PARITY
- CMP AH,'a' ;IS IT GREATER THAN LOWER A?
- JL NOOUPR ;NOPE, IT'S NOT LOWER
- CMP AH,'z' ;IS IT GREATER THAN LOWER Z?
- JG NOOUPR ;NOPE, STILL NOT LOWER
- AND AL,NOT 020H ;YES, WHACK OUT THE LOWER BIT.
- NOOUPR:
- ;
- ; AFTER ALL THE SPECIAL OUTPUT PROCESSING, I DO A HARD WAIT
- ; FOR A SLOT IN THE OUTPUT BUFFER.
- WWAIT:
- CALL PUT_OUT ;ATTEMPT TO PUT IN IN OUTPUT BUFFER
- CMP AH,0 ;DID IT WORK?
- JNE WWAIT ;NO, KEEP TRYING.
- LOOP WLUP ;YES, GO GET NEXT CHAR.
- CALL START_OUTPUT ;START THE XMITTER IF NECC.
- WRSUCC:
- MOV AX,0 ;RETURN SUCCESS
- JMP EXIT
- SUBTTL OUTPUT STATUS REQUEST ROUTINE
- ; OUTPUT STATUS REQUEST
- ;
- TXSTAT:
- MOV AX,OFIRST[SI] ;GET POINTER TO NEXT CHAR OUT
- DEC AX ;SUBTRACT ONE FROM IT,
- AND AX,BUFMSK ;MODULO 128.
- CMP AX,OAVAIL[SI] ;IF THAT EQUALS THE INPUT PNTR,
- JNE TXROOM
- MOV AX,STSBSY ;THEN THE DEVICE IS BUISY.
- JMP EXIT
- TXROOM:
- MOV AX,0 ;OTHERWIZE THE DEVICE IS OK.
- JMP EXIT
- SUBTTL I/O CONTROL READ REQUEST
- PAGE
- ;
- ; IOCONTROL READ REQUEST, RETURN LINE PARAMETERS
- ;
- IOCTLIN:
- MOV CX,ES:COUNT[BX] ;GET THE REQUESTED NUMBER OF BYTES
- MOV DI,ES:XFER[BX] ;DI IS OFFSET TO USER BUFFER
- MOV DX,ES:XSEG[BX] ;SEGMENT IS LAST I NEED FROM PACKET,
- MOV ES,DX ;NOW ES:DI POINTS TO USER BUFFER.
- CMP CX,10 ;ONLY WORKS WHEN YOU GIVE ME AN
- JE DOIOCIN ;10 BYTE BUFFER TO STOMP ON.
- MOV AX,ERRBSL ;RETURN AN ERROR IF NOT 10 BYTES.
- JMP EXIT
- DOIOCIN:
- MOV DX,PORT[SI] ;GET PORT NUMBER
- ADD DX,LCTRL ;SLIDE UP TO LINE CONTROL
- MOV CX,4 ;SET UP FOR PORT LOOP.
- GETPORT:
- IN AL,DX ;GET NEXT BYTE FROM DEVICE
- STOS BYTE PTR [DI] ;STORE THEM IN USER BUFFER
- INC DX ;SKIP TO NEXT BYTE
- LOOP GETPORT ;READ AND STORE 4 BYTES OF INFO
-
- MOV AX,INSPEC[SI] ;GET THE SPECIAL INPUT BITS
- STOS WORD PTR [DI] ;SEND BACK TO USER BUFFER
- MOV AX,OUTSPEC[SI] ;GET THE SPECIAL OUTPUT BITS
- STOS WORD PTR [DI] ;SEND BACK TO USER BUFFER
- MOV AX,BAUD[SI] ;GET BAUD RATE DIVISOR
- MOV BX,DI ;SAVE DI FOR A WHILE.
- MOV DI,OFFSET ASY_BAUDT+2 ;POINT AT BAUD RATE CONVERSION.
- MOV CX,15 ;JUST IN CASE, STOP AT 15 BAUDS
- BAUDCIN:
- CMP [DI],AX ;IS THIS THE BAUD I AM USING?
- JE YESINB ;YES, RETURN THAT
- ADD DI,4 ;NO, SKIP TO NEXT ONE
- LOOP BAUDCIN ;KEEP LOOKING.
- YESINB: ;SEARCH SHOULD ALWAYS TERMINATE ON COMPARE
- MOV AX,-2[DI] ;GET THE ASSOCIATED BAUD RATE
- MOV DI,BX ;GET DI'S OLD VALUE BACK
- STOS WORD PTR [DI] ;STORE THE BAUD RATE BACK.
- MOV AX,0 ;RETURN NO ERRORS
- JMP EXIT
-
- ;
- ; FLUSH OUTPUT BUFFER REQUEST
- ;
- TXFLUSH:
- MOV AX,OAVAIL[SI] ;GET NEXT FREE BYTE OFFSET,
- MOV OFIRST[SI],AX ;POINT THE FIRST BYTE OFFSET AT IT.
- MOV AX,0
- JMP EXIT
- SUBTTL I/O CONTROL WRITE REQUEST ROUTINE
- PAGE
- ; IOCONTROL REQUEST: CHANGE LINE PARAMETERS FOR THIS DRIVER
- ;
- IOCTLOUT:
- MOV CX,ES:COUNT[BX] ;GET THE REQUESTED NUMBER OF BYTES
- MOV DI,ES:XFER[BX] ;DI IS OFFSET TO USER BUFFER
- MOV DX,ES:XSEG[BX] ;SEGMENT IS LAST I NEED FROM PACKET,
- MOV ES,DX ;NOW ES:DI POINTS TO USER BUFFER.
- CMP CX,10 ;ONLY WORKS WHEN YOU GIVE ME A
- JE DOIOCOUT ;10 BYTE BUFFER TO READ FROM
- MOV AX,ERRBSL ;RETURN AN ERROR IF NOT 10 BYTES.
- JMP EXIT
- DOIOCOUT:
- MOV DX,PORT[SI] ;GET PORT NUMBER
- ADD DX,LCTRL ;SLIDE UP TO LINE CONTROL
- MOV AL,ES:[DI] ;GET LINE CONTROL FROM USER BUF.
- INC DI
- OR AL,080H ;SET DLAB BIT FOR BAUD RATE
- OUT DX,AL ;OUTPUT TO DEVICE
- INC DX ;SKIP TO NEXT BYTE
- MOV AL,ES:[DI] ;GET MODEM CONTROL FROM USER BUF.
- INC DI
- OR AL,08H ;MAKE SURE INTERUPTS ARE ENABLED.
- OUT DX,AL ;SEND IT TO DEVICE.
- ADD DI,2 ;SKIP OVER THE STATUS BYTES
- MOV AX,ES:[DI] ;GET THE SPECIAL INPUT BITS
- ADD DI,2
- MOV INSPEC[SI],AX ;STORE THE NEW BITS IN UNIT
- MOV AX,ES:[DI] ;GET THE OUTPUT SPECIAL BITS
- ADD DI,2
- MOV OUTSPEC[SI],AX ;STORE THEM ALSO.
- MOV AX,ES:[DI] ;GET THE REQUESTED BAUD RATE
- MOV BX,DI ;SAVE DI FOR A WHILE.
- MOV DI,OFFSET ASY_BAUDT ;POINT AT BAUD RATE CONVERSION
- MOV CX,15 ;JUST IN CASE, STOP AT 15 BAUDS
- BAUDCOUT:
- CMP [DI],AX ;IS THIS THE BAUD I AM USING?
- JE YESOUTB ;YES, RETURN THAT
- ADD DI,4 ;NO, SKIP TO NEXT ONE
- LOOP BAUDCOUT ;KEEP LOOKING.
- IN AL,DX ;GET LINE CONTROL REGESTER AGAIN,
- AND AL,NOT 080H ;CLEAR DLAB BIT.
- DEC DX
- OUT DX,AL ;AND WRITE IT BACK OUT.
- MOV AX,ERRUM ;RETURN AN ERROR NUMBER IF
- JMP EXIT ;BAUD RATE IS NOT IN TABLE.
- YESOUTB:
- MOV AX,2[DI] ;GET THE ASSOCIATED BAUD RATE
- MOV BAUD[SI],AX ;STORE IT IN UNIT TABLE
- MOV DX,PORT[SI] ;GET PORT ADDRESS AGAIN,
- OUT DX,AL ;WRITE THE LOW BYTE,
- INC DX ;SKIP TO NEXT ONE,
- MOV AL,AH ;GET HIGH BYTE INTO AL
- OUT DX,AL ;OUTPUT IT AS WELL.
- ADD DX,LCTRL-BAUD1 ;POINT AT THE LINE CONTROL REG.
- IN AL,DX ;READ IT IN,
- AND AL,NOT 080H ;CLEAR THE DLAB BIT.
- OUT DX,AL ;OUTPUT IT BACK.
- MOV AX,0 ;RETURN NO ERROR
- JMP EXIT
- SUBTTL RING BUFFER ROUTINES
- PAGE
- ; LOCAL ROUTINES FOR MANAGING THE RING BUFFERS ON INPUT
- ; AND OUTPUT. THE FOLLOWING FOUR ROUTINES ARE ALL CALLED WITH THE
- ; SAME CONTEXT:
- ;
- ; DS:SI POINTS TO THE UNIT STRUCTURE FOR THIS UNIT
- ; AL IS THE CHARACTER TO BE PLACED IN OR REMOVED FROM A BUFFER
- ; AH IS THE RETURN STATUS FLAG: 0=SUCESS, -1=FAILURE
- ;
- ; ALL OTHER REGESTERS ARE PRESERVED.
- ;
- PUT_OUT PROC NEAR ;PUTS AL INTO THE OUTPUT RING BUFFER
- PUSH CX
- PUSH DI
- PUSHF
- CLI ;DISABLE INTERUPTS WHILE I HAVE OAVAIL
- MOV CX,OAVAIL[SI] ;GET POINTER TO NEXT AVAILABLE BYTE IN
- MOV DI,CX ;OUTPUT BUFFER.
- INC CX ;INCRIMENT A COPY OF IT TO SEE IF THE
- AND CX,BUFMSK ;BUFFER IS FULL.
- CMP CX,OFIRST[SI] ;IS IT?
- JE POERR ;YES, RETURN AN ERROR
- ADD DI,OBUF[SI] ;NO, CALCULATE ACTUAL OFFSET OF CHAR
- MOV [DI],AL ;AND STUFF THE CHARACTER INTO BUFFER
- MOV OAVAIL[SI],CX ;UPDATE THE POINTER
- MOV AH,0 ;INDICATE SUCCESS
- JMP PORET ;AND RETURN
- POERR:
- MOV AH,-1 ;INDICATE FAILURE.
- PORET:
- POPF ;RE-ENABLE INTERUPTS
- POP DI
- POP CX
- RET
- PUT_OUT ENDP
-
- GET_OUT PROC NEAR ;GETS THE NEXT CHARACTER FROM OUTPUT RING BUFFER
- ;SURE YOU DISABLE INTERUPTS FIRST.
- PUSH CX
- PUSH DI
- PUSHF ;JUST IN CASE, DISABLE INTERUPTS
- CLI ;WHILE IN THIS ROUTINE.
- MOV DI,OFIRST[SI] ;GET POINTER TO FIRST CHARACTER TO OUTPUT
- CMP DI,OAVAIL[SI] ;IS THE BUFFER EMPTY?
- JNE NGOERR ;NO.
- MOV AH,-1 ;YES, INDICATE FAILURE
- JMP GORET ;AND RETURN
- NGOERR:
- MOV CX,DI ;SAVE A COPY OF THE POINTER
- ADD DI,OBUF[SI] ;CALCULATE ACTUAL ADDRESS
- MOV AL,[DI] ;GET THE CHAR INTO AL
- MOV AH,0 ;INDICATE SUCCESS.
- INC CX ;INCRIMENT THE OFFSET
- AND CX,BUFMSK ;MODULO 128
- MOV OFIRST[SI],CX ;STORE BACK IN UNIT TABLE.
- GORET:
- POPF
- POP DI
- POP CX
- RET
- GET_OUT ENDP
-
- PUT_IN PROC NEAR ;PUT THE CHAR FROM AL INTO INPUT RING BUFFER
- PUSH CX
- PUSH DI
- PUSHF ;DISABLE INTS WHILE IN THIS ROUTINE
- CLI
- MOV DI,IAVAIL[SI] ;GET POINTER TO NEXT AVAILABLE SLOT IN BUFFER
- MOV CX,DI ;SAVE A COPY OF IT,
- INC CX ;AND INCRIMENT THAT COPY (MODULO
- AND CX,BUFMSK ;128) TO SEE IF THE BUFFER IS FULL.
- CMP CX,IFIRST[SI] ;WELL, IS IT?
- JNE NPIERR ;NO, THERE`S ROOM.
- MOV AH,-1 ;YES, INDICATE FAILURE
- JMP PIRET ;AND RETURN
- NPIERR:
- ADD DI,IBUF[SI] ;CALCULATE ACTUAL ADDRES,
- MOV [DI],AL ;STORE THE CHARACTER THERE
- MOV IAVAIL[SI],CX ;UPDATE THE POINTER.
- MOV AH,0 ;AND INDICATE SUCCESS.
- PIRET:
- POPF
- POP DI
- POP CX
- RET
- PUT_IN ENDP
-
- GET_IN PROC NEAR ;GETS ONE CARACTER FROM INPUT RING BUFFER INTO AL
- PUSH CX
- PUSH DI
- PUSHF
- CLI ;DISABLE INTERUPTS WHILE I LOOK AT IFIRST.
- MOV DI,IFIRST[SI] ;GET POINTER TO FIRST CHAR TO READ
- CMP DI,IAVAIL[SI] ;IS THE BUFFER EMPTY?
- JE GIERR ;THEN YOU CAN`T VERY WELL SQUEEZE WATER OUT OF IT
- MOV CX,DI ;MAKE A COPY OF POINTER,
- ADD DI,IBUF[SI] ;CALCULATE ACTUAL ADDRESS OF CHAR
- MOV AL,[DI] ;GET THE CHAR INTO AL
- MOV AH,0 ;INDICATE SUCCESS
- INC CX ;INCRIMENT THAT COPY OF YOUR POINTER,
- AND CX,BUFMSK ;MODULO THE BUFFER SIZE,
- MOV IFIRST[SI],CX ;SO YOU CAN UPDATE THE POINTER.
- JMP GIRET
- GIERR:
- MOV AH,-1 ;RETURN FAILURE INDICATOR
- GIRET:
- POPF ;RE-ENABLE INTERUPTS BEFORE YOU RETURN
- POP DI
- POP CX
- RET
- GET_IN ENDP
- SUBTTL INTERUPT SERVICE ROUTINES
- PAGE
- ; THE FOLLOWING ROUTINES ARE WHAT I REALLY CALL AN INTERUPT
- ; ROUTINE! THESE ROUTINES ARE ONLY CALLED WHEN AN INTERUPT IS GENERATED
- ; BY THE 8088, NOT BY A SOFWARE CALL THROUGH A LINKED LIST! ONE EASY
- ; WAY TO TELL A REAL INTERUPT ROUTINE WHEN YOU SEE IT IS TO LOOK AT THE
- ; LAST INSTRUCTION, WHICH IS AN "INTERUPT RETURN", NOT A FAR RETURN
- ; LIKE THE SO-CALLED MSDOS "INTERUPT ROUTINE" DOES.
- ; THESE INTERUPT ROUTINES ARE ENVOKED WHENEVER A CHAR ARRIVES IN THE
- ; UART, THE UART FINISHES SENDING A CHARACTER OUT, AN ERROR OCCURS
- ; WHILE READING A CHARACTER INTO THE UART, OR THE MODEM STATUS LINES
- ; CHANGE.
-
- ASY1ISR:
- CLI
- PUSH SI
- LEA SI,ASY_TAB1 ;POINT AT THE CORRECT TABLE FOR THIS UART,
- JMP INT_SERVE ;JUMP INTO THE COMMON INTERUPT SERVER CODE.
- ASY2ISR:
- CLI
- PUSH SI
- LEA SI,ASY_TAB2 ;GET UNIT TABLE
- ;
- ; IF YOU ADD MORE UNITS, YOU CAN ADD THEM HERE,
- ; BUT DON'T FORGET TO ADD A JUMP INT_SERVE AFTER
- ; ASY2ISR'S LEA INSTRUCTION!
- ;
- ; THE FOLLOWING CODE IS THE COMMON SHARED CODE THAT ALL THE
- ; ASYNC PORTS SHARE. IT "KNOWS" WHICH ONE TO TALK TO BY REFERENCING
- ; THE STRUCTURE POINTED TO BY CS:SI.
-
- INT_SERVE:
- PUSH AX ;PUSH ALL THE GP REGESTERS
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DI
- PUSH DS ;SAVE THE DATA SEGMENT
- PUSH CS ;SO YOU CAN LOAD CS
- POP DS ;INTO DS AND FIND YOUR OWN STRUCTURES.
- INT_EXIT:
- MOV DX,PORT[SI] ;GET THE PORT ADDRESS OF THIS DEVICE
- ADD DX,INTID ;SLIDE UP TO THE INTERUPT ID REGISTER
- IN AL,DX ;GET THE INTERUPT REASON
- TEST AL,1 ;MAKE SURE IT IS VALID
- JNE INT_DONE ;IT IS NOT.
- MOV AH,0 ;CONVERT IT TO A 16 BIT NUMBER
- ADD AX,OFFSET INT_REASON ;ADD IT TO THE JUMP TABLE ADDRESS
- MOV DI,AX ;PUT IT IN AN INDEX REGESTER,
- JMP [DI] ;AND GO PROCESS THAT TYPE OF INTERUPT
-
- INT_DONE:
- ADD DX,LSTAT-INTID ;BECAUSE IT SEEMS TO BE NECESSARY,
- IN Al,DX ;READ THE STATUS PORT BEFORE YOU EXIT.
- MOV AL,020H ;OUTPUT A 20H TO THE UNDOCUMENTED INTERUPT
- OUT 020H,AL ;COMMAND PORT TO ENABLE FURTHER INTERUPTS?
- POP DS ;RECOVER ALL THE REGESTERS
- POP DI
- POP DX
- POP CX
- POP BX
- POP AX
- POP SI
- IRET
-
- ;
- ; JUMP TABLE OF INTERUPT REASONS. INTERUPT ID REGISTER
- ; IS USED AS INDEX TO THIS TABLE.
- INT_REASON:
- DW INT_MODEM ;INT WAS CAUSED BY A MODEM LINE TRANSITION
- DW INT_TXMIT ;INT WAS CAUSED BY A TX REGISTER EMPTY
- DW INT_RECEIVE ;NEW CHARACTER AVAILABLE IN UART
- DW INT_RXSTAT ;CHANGE IN RECEIVER STATUS REGESTER
- SUBTTL RECEIVER INTERUPT SERVICE ROUTINE
- PAGE
- ;
- ; THE INTERUPT SERVICE ROUTINES BELOW ALL HAVE THE
- ; FOLLOWING CONTEXT:
- ; -CS AND DS POINT TO THE DRIVER SEGMENT.
- ; -DS:[SI] POINTS TO THE UNIT STRUCTURE FOR THE ASYNC LINE THAT
- ; FIRED THE INTERUPT.
- ; -AX BX CX DX AND DI ARE AVAILABLE FOR SCRATCH. ALL OTHERS
- ; MUST BE LEFT ALONE OR SAVED AND RECOVERED.
- ; TO EXIT FROM AN INTERUPT SERVICE ROUTINE, THESE SERVERS MUST
- ; JUMP TO INT_EXIT.
- ;
- SUBTTL RECEIVER INTERUPT SERVICE ROUTINE
- INT_RECEIVE: ;THE UART HAS RECEIVED A NEW CHARACTER, I MUST COPY IT
- ;INTO THE INPUT TYPEAHEAD BUFFER.
- MOV DX,PORT[SI] ;POINT DX BACK AT THE RXBUF REGESTER
- IN AL,DX ;GET THE CHARACTER
- ;
- ; BEFORE I STORE THE CHARACTER BACK IN THE RING
- ; BUFFER, I CHECK TO SEE IF ANY OF THE SPECIAL
- ; INPUT SEQUENCES ARE ENABLED, AND IF THEY
- ; HAVE BEEN FOUND IN THE INPUT.
- ;
- ;
- ; CHECK FOR XON/XOFF
- ;
- TEST OUTSPEC[SI],OUTXON ;IS XON/XOFF ENABLED?
- JE NOXON ;NO, SKIP THIS WHOLE SECTION
- CMP AL,'S' AND 01FH ;IS THIS A CONTROL-S?
- JNE ISQ ;NO, CHECK FOR CONTROL-Q
- OR LINE[SI],LINXOF ;DISABLE OUTPUT.
- JMP INT_EXIT ;DON'T STORE THIS CHAR.
- ISQ:
- CMP AL,'Q' AND 01FH ;IS THIS A CONTROL-Q?
- JNE NOXON ;NO, SKIP TO THE NEXT TEST.
- TEST LINE[SI],LINXOF ;AM I WAITING FOR THIS ^Q?
- JE INT_EXIT ;NO, DON'T STIR UP DRIVER.
- AND LINE[SI],NOT LINXOF ;CLEAR THE XOFF BIT,
- CALL START_OUTPUT
- JMP INT_EXIT ;DON'T BUFFER ^Q'S
- NOXON:
- ;
- ; CHECK FOR THE SKIP OUTPUT ESCAPE SEQUENCE
- ;
- TEST INSPEC[SI],INCTO ;IS THIS ENABLED?
- JE NOCTO ;NOPE.
- MOV DI,SKIPP[SI] ;GET OFFSET TO NEXT CHAR
- MOV SKIPP[SI],0 ;RESET RECOG. OF THIS SEQ.
- CMP SKIPO[DI],AL ;THIS IT?
- JNE NOCTO ;NOPE, GO CHECK FOR OTHERS.
- INC DI ;YES, INCRIMENT TO NEXT CHAR.
- CMP SKIPO[DI],0 ;WAS THAT THE LAST ONE?
- JNE NEXTO ;NO, PASS THIS CHAR ON.
- XOR LINE[SI],LINSKP ;YES, TOGGLE THE SKIP BIT.
- CALL START_OUTPUT ;RATTLE THE XMITTERS CAGE.
- INT_EXIT3:
- JMP INT_EXIT ;AND EXIT.
- NEXTO:
- MOV SKIPP[SI],DI ;SET OFFSET TO NEXT CHAR.
- NOCTO:
-
- ;
- ; CHECK FOR THE FLUSH INPUT BUFFER SEQUENCE.
- ;
- TEST INSPEC[SI],INCTX ;IS THIS ENABLED?
- JE NOCTX ;NOPE.
- MOV DI,FLSHP[SI] ;GET OFFSET TO NEXT CHAR
- MOV FLSHP[SI],0 ;RESET RECOG. OF THIS SEQ.
- CMP FLUSH[DI],AL ;THIS IT?
- JNE NOCTX ;NOPE, GO CHECK FOR OTHERS.
- INC DI ;YES, INCRIMENT TO NEXT CHAR.
- CMP FLUSH[DI],0 ;WAS THAT THE LAST ONE?
- JNE NEXTX ;NO, PASS THIS CHAR ON.
- MOV AX,IFIRST[SI] ;YES! FLUSH THE BUFFER BY
- MOV IAVAIL[SI],AX ;POINTING INPUT TO OUTPUT.
- JMP INT_EXIT ;AND EXIT.
- NEXTX:
- MOV FLSHP[SI],DI ;SET OFFSET TO NEXT CHAR.
- NOCTX:
- ;
- ; CHECK FOR THE RE-BOOT SYSTEM ESCAPE SEQUENCE.
- ;
- TEST INSPEC[SI],INRES ;IS THIS ENABLED NOW?
- JE NOREB ;NO.
- MOV DI,REBTP[SI] ;GET OFFSET TO NEXT CHAR
- MOV REBTP[SI],0 ;RESET RECOG. OF THIS SEQ.
- CMP REBOOT[DI],AL ;THIS IT?
- JNE NOREB ;NOPE, GO CHECK FOR OTHERS.
- INC DI ;YES, INCRIMENT TO NECT CHAR.
- CMP REBOOT[DI],0 ;WAS THAT THE LAST ONE?
- JNE NEXTB ;NO, PASS THIS CHAR ON.
- MOV AX,0 ;YES, SET UP TO DO A KEYBOARD
- MOV DS,AX ;RESET.
- ASSUME DS:VECS
- MOV AX,1232H ;GET THE QUICK BOOT FLAG,
- MOV FLAG,AX ;WARN RESET THIS IS QUICK BOOT
- JMP RE_BOOT ;JUMP TO THE RE-BOOT VECTOR.
-
- NEXTB:
- MOV REBTP[SI],DI ;SET OFFSET TO NEXT CHAR.
- NOREB:
- ;
- ; CHECK FOR THE RE-DRAW LAST LINE SEQUENCE.
- ;
- TEST INSPEC[SI],INCTR ;IS THIS ENABLED?
- JE NOCTR ;NOPE.
- MOV DI,REDRP[SI] ;YES, GET POINTER TO NEXT
- MOV REDRP[SI],0 ;RESET IN CASE THIS ISNT IT.
- CMP REDRAW[DI],AL ;IS THIS THE NEXT CHAR?
- JNE NOCTR ;NO.
- INC DI ;YES, INCRIMENT TO NEXT
- CMP REDRAW[DI],0 ;WAS THAT THE LAST ONE?
- JNE NEXTR ;NO, PASS THIS CHAR ON.
- MOV DI,OFIRST[SI] ;YES, THEN SEARCH BACKWARDS
- MOV BX,OBUF[SI] ;FOR THE LAST CR.
- CRLUP:
- DEC DI ;STEP BACK ONE CHAR IN TIME
- AND DI,BUFMSK ;(MODULO THE BUFFER SIZE)
- CMP DI,OAVAIL[SI] ;BUT STOP IF YOU BACK INTO
- JE NOCTR ;THE OTHER END OF BUFFER
- CMP BYTE PTR [BX+DI],0DH ;IS THIS A CR?
- JNE CRLUP ;NO, KEEP LOOKING.
- MOV OFIRST[SI],DI ;YES, SET BUFFER BACK.
- CALL START_OUTPUT ;AND MAKE SURE XMITTER SEES IT.
- INT_EXIT2:
- JMP INT_EXIT
- NEXTR:
- MOV REDRP[SI],DI ;UPDATE PTR TO PARTIAL SEQ.
- NOCTR:
- ;
- ; CHECK FOR THE ERASE TO BEGENING OF LINE ESCAPE SEQ.
- ;
- TEST INSPEC[SI],INCTU ;IS THIS ENABLED?
- JE NOCTU ;NOPE.
- MOV DI,BACKP[SI] ;YES, GET POINTER TO NEXT
- MOV BACKP[SI],0 ;RESET IN CASE THIS ISNT IT.
- CMP BACKL[DI],AL ;IS THIS THE NEXT CHAR?
- JNE NOCTU ;NO.
- INC DI ;YES, INCRIMENT TO NEXT
- CMP BACKL[DI],0 ;WAS THAT THE LAST ONE?
- JNE NEXTU ;NO, PASS THIS CHAR ON.
- MOV DI,IFIRST[SI] ;YES, THEN SEARCH BACKWARDS
- MOV BX,IBUF[SI] ;FOR THE LAST CR.
- MOV CX,-1 ;COUNTING THEM IN CX.
- BCRLUP:
- INC CX
- DEC DI ;STEP BACK ONE CHAR IN TIME
- AND DI,BUFMSK ;(MODULO THE BUFFER SIZE)
- CMP DI,IAVAIL[SI] ;BUT STOP IF YOU BACK INTO
- JE NOCTU ;THE OTHER END OF BUFFER
- CMP BYTE PTR [BX+DI],0DH ;IS THIS A CR?
- JNE BCRLUP ;NO, KEEP LOOKING.
- ;NOW CX CONTAINS THE NUMBER OF CHARACTERS TO
- ;DELETE. I DO THIS THE DUMB WAY: BY SENDING
- ;THAT MANY BACKSPACE CHARACTERS
- MOV AL,8 ;PUT A BACKSPACE IN AL
- BAKLUP:
- CALL PUT_IN ;PUT IT IN THE INPUT BUFFER
- LOOP BAKLUP ;PUT IN A BUNCH OF THEM
- JMP INT_EXIT ;WON'T MSDOS BE SUPRISED?
- NEXTU:
- MOV BACKP[SI],DI ;UPDATE PTR TO PARTIAL SEQ.
- NOCTU:
- ;
- ; NONE OF THE SPECIAL INPUT SEQUENCES PANNED OUT, SO
- ; I'LL JUST STUFF THE CHARACTER INTO THE INPUT RING
- ; BUFFER THIS TIME.
- STUFF_IN:
- CALL PUT_IN ;PUT THE CHARACTER IN THE RING BUFFER
- CMP AH,0 ;WAS THERE ROOM?
- JE INT_EXIT2 ;YES, JUST RETURN
- OR MODEM[SI],MODOVR ;NO, SET THE OVERFLOW BIT
- TEST INSPEC[SI],INBEL ;ARE OVERFLOW BELLS ENABLED?
- JE INT_EXIT2 ;NO, SKIP IT.
- TEST LINE[SI],LINEXP ;IS XMITTER EXPECTING AN INTERUPT?
- JNE INT_EXIT2 ;YES, LEAVE HIM ALONE.
- MOV AL,7 ;NO, SEND A BELL IMMEDIATELY
- MOV DX,PORT[SI] ;GET PORT ADDRESS,
- OUT DX,AL ;AND SEND A CHAR TO XMITTER TO START
- OR LINE[SI],LINEXP ;SET INTERUPT EXPECTED BIT.
- JMP INT_EXIT
- SUBTTL RECEIVER LINE STATUS INTERUPT ROUTINE
- PAGE
- ; THE LSTAT REGISTER DETECTED A RECEIVER ERROR CONDITION
- INT_RXSTAT:
- ADD DX,LSTAT-INTID ;READ THE REGESTER AND FIND OUT WHY
- IN AL,DX
- TEST INSPEC[SI],INEPC ;DO I RETURN THEM AS CODES?
- JE NOCODE ;NO, WHAT ELSE?
- AND AL,01EH ;YES, MASK OFF ALL BUT ERROR BITS,
- OR AL,080H ;SET THE PARITY BIT TO MAKE IT
- ;AN ILLEGAL CHARACTER,
- JMP STUFF_IN ;AND PUT IT IN THE INPUT BUFFER.
- NOCODE:
- OR MODEM[SI],MODERR ;SET A STATUS BIT THAT WILL
- ;NOTIFY MSDOS ON THE NEXT REQUEST
- JMP INT_EXIT
- PAGE
- SUBTTL MODEM STATUS INTERUPT SERVICE ROUTINE
- ; THE MODEM STATUS REGESTER DETECTED A CHANGE IN ONE OF THE
- ; MODEM LINES. I COULD CHECK THE "DELTA BITS" TO SEE EXACTLY WHICH
- ; LINE TRIGGERED THIS INTERUPT, BUT I JUST CHECK ALL OF THEM WHEN
- ; I GET ANY MODEM STATUS INTERUPT.
- INT_MODEM:
- ADD DX,MSTAT-INTID ;READ THE MODEM STATUS REGESTER
- IN AL,DX
- ;*********************************
- ;CHECK THE CARIER-DETECT BIT (CD)
- TEST AL,080H ;IS CARRIER DETECT OFF?
- JNE MSDSR ;NO, CHECK DSR NEXT
- TEST OUTSPEC[SI],OUTCDF ;IS CD THE OFF-LINE SIGNAL?
- JE MSDSR ;NO, IGNORE CD THEN.
- OR MODEM[SI],MODOFF ;YES,SET OFLINE FOR NEXT READ REQUEST
- ;**************************************
- ;CHECK THE DATA-SET-READY BIT (DSR)
- MSDSR:
- TEST AL,020H ;IS DSR OFF?
- JNE DSRON ;NO, GO CHECK TO SEE IF I WAS WAITING ON IT.
- TEST OUTSPEC[SI],OUTDSR ;IS DSR THE OUTPUT DATA THROTTLE FLG?
- JE DSROFF ;NO, MABY IT'S OFFLINE SIGNAL
- OR LINE[SI],LINDSR ;YES, SUSPEND OUTPUT WAITING ON DSR
- DSROFF:
- TEST OUTSPEC[SI],OUTDRF ;IS DSR THE OFFLINE SIGNAL?
- JE MSCTS ;NOPE.
- OR MODEM[SI],MODOFF ;YES, SET FLAG FOR NEXT READ.
- JMP MSCTS
- DSRON:
- TEST LINE[SI],LINDSR ;WAS I WAITING FOR DSR TO COME ON?
- JE MSCTS ;NO, IGNORE IT.
- AND LINE[SI],NOT LINDSR ;YES, CLEAR THE BIT, AND
- CALL START_OUTPUT ;START OUTPUT BACK UP AGAIN.
- ;****************************************
- ;CHECK THE CLEAR-TO-SEND BIT (CTS)
- MSCTS:
- TEST AL,010H ;IS CTS OFF?
- JNE CTSON ;NO, GO CHECK TO SEE IF ITS EXPECTED
- TEST OUTSPEC[SI],OUTCTS ;IS CSR THE OUTPUT DATA THROTTLER?
- JE CTSOFF ;NO, MABY IT'S OFFLINE SIGNAL
- OR LINE[SI],LINCTS ;YES, SUSPEND OUTPUT.
- CTSOFF:
- TEST OUTSPEC[SI],OUTCTS ;IS CTS THE OFF-LINE SIGNAL?
- JE INT_EXIT4 ;NOPE.
- OR MODEM[SI],MODOFF ;YES, SET FLAG FOR NEXT READ.
- JMP INT_EXIT
- CTSON:
- TEST LINE[SI],LINCTS ;WAS I WAITING FOR THIS CTS?
- JE INT_EXIT4 ;NO, THERE'S NOTHING LEFT TO CHECK.
- AND LINE[SI],NOT LINCTS ;YES, CLEAR THE BIT, AND
- CALL START_OUTPUT ;START OUTPUT UP AGAIN.
- INT_EXIT4:
- JMP INT_EXIT
- SUBTTL TRANSMITTER INTERUPT SERVICE ROUTINE
- PAGE
- ; THE TRANSMITTER HOLDING REGESTER IS EMPTY, LOOK TO SEE IF
- INT_TXMIT: ;THERE ARE MORE CHARS TO PRINT NOW.
- AND LINE[SI],NOT LINEXP ;CLEAR INTERUPT EXPECTED BIT.
- CALL START_OUTPUT ;START THE NEXT CHARACTER
- JMP INT_EXIT
-
- ;ROUTINE TO START THE NEXT CHARACTER PRINTING ON THE UART, IF OUTPUT
- ;IS NOT BEING SUSPENDED FOR ONE REASON OR ANOTHER.
- ;THIS ROUTINE MAY BE CALLED FROM REQUEST ROUTINES, OR FROM INTERUPT
- ;SEVICE ROUTINES.
- ; THIS ROUTINE DESTROYS AX AND DX.
- ; SX MUST POINT AT THE UNIT STRUCTURE.
- START_OUTPUT PROC NEAR
- PUSHF ;SAVE THE FLAGS SO I CAN
- CLI ;DISABLE INTERUPTS
- TEST LINE[SI],LINIDL ;AM I IN HOLD OUTPUT MODE?
- JNE DONT_START ;YES, DON'T SEND ANY MORE CHARS.
- CALL GET_OUT ;CHECK TO SEE IF THERE IS A CHAR IN THE BUF
- CMP AH,0 ;WELL, WAS THERE?
- JNE DONT_START ;NO, BUFFER IS EMPTY
- MOV DX,PORT[SI] ;YES, POINT DX AT THE TX OUT REGISTER
- OUT DX,AL ;SEND HIM THE CHARACTER
- OR LINE[SI],LINEXP ;WARN EVERYBODY THAT I'M BUSY.
- DONT_START:
- POPF
- RET
- START_OUTPUT ENDP
-
- ; THE FOLLOWING LABEL DEFINES THE END OF THE DRIVER, SO I
- ; CAN TELL DOS HOW BIG I AM.
- ASYNC_END:
- SUBTTL INITIALIZATION REQUEST ROUTINE
- PAGE
- ;
- ; THE INITIALIZE DRIVER ROUTINE IS STORED AFTER THE "END"
- ; OF THE DRIVER HERE SO THAT THIS CODE CAN BE THROWN AWAY AFTER
- ; THE DEVICE HAS BEEN INITIALIZED. THIS CODE IS ONLY CALLED TWICE:
- ; ONCE TO INITIALIZE EACH OF THE ASYNC UNITS THAT THIS DRIVER
- ; CONTAINS. (HOPEFULLY, MSDOS DOESN'T WRITE ANYTHING ON TOP OF
- ; THIS CODE UNIT BOTH UNITS ARE INITIALIZED.
- ; THE CONTEXT OF THE INITIALIZE CODE BELOW IS THE SAME AS
- ; ALL THE OTHER REQUEST ROUTINES EARLIER IN THE DRIVER.
- ;
- ; INITIALIZE THE DRIVER AND DEVICE
- ;
- ASYNC_INIT:
- MOV AX,OFFSET ASYNC_END ;GET THE SIZE OF THE DRIVER
- MOV ES:XFER[BX],AX ;SEND THAT BACK IN PACKET
- MOV ES:XSEG[BX],CS ;SEND THE CODE SEGMENT ALSO.
- ;I HAVE SATISFIED ALL THE REQIREMENTS OF THE
- ;INIT FUNCTION TO RETURN IN THE I/O PACKET, SO
- ;I CAN DESTROY THE CONTENTS OF ES:BX AND USE
- ;THEM FOR OTHER THINGS.
- MOV AX,0 ;POINT ES AT THE VECTOR SEGMENT
- MOV ES,AX ;SO CAN INITIALIZE THE VECTORS
- MOV AX,ISRADR[SI] ;GET ADRS OF INTERUPT SERVICE ROUTINE
- ;THE FOLLOWING CODE IS SPECIFIC TO THE IBM:
- ;BASIC USES LOCATIONS 400 AND 402 TO FIND
- ;THE PORT ADDRESSES OF COM1 AND COM2. IF I
- ;ZERO THESE, THEN BASIC CANNOT MUCK UP THE
- ;REGESTERS ON ME ANY MORE! (IT STILL
- ;DISABLES INTERUPTS, THOUGH. BUMMER!)
- MOV DI,400 ;POINT AT THE ASYNC ADDRESS LIST
- CLD
- STOS WORD PTR [DI] ;CLOBBER THE FIRST ONE,
- STOS WORD PTR [DI] ;AND THE SECOND ONE.
- ;NOW WE'RE BACK ON THE GENERIC MSDOS TRACK.
- MOV DI,VECT[SI] ;GET ADRS OF VECOTR,
- STOS WORD PTR [DI] ;STORE THE OFFSET THERE, THEN
- MOV ES:[DI],CS ;THE SEGMENT IN THE FOLLOWING WORD.
- MOV CX,DI ;GET THE VECTOR NUMBER,
- SUB CL,022H ;SUBTRACT BIAS TO HARDWARE INTS,
- SAR CL,1 ;DIVIDE BY 4 TO CONVERT TO
- SAR CL,1 ;HARDWARE INTERUPT NUMBER.
- MOV AH,1 ;SHIFT A MASK BY THAT MUCH TO
- SAL AH,CL ;CREATE INTERUPT ENABLE MASK BIT,
- NOT AH ;WHICH IS ACTIVE LOW...
- IN AL,021H ;GET SYSTEM HARDWARE INTERUPT MASK
- AND AL,AH ;AND MY BIT OUT OF IT,
- OUT 021H,AL ;WRITE IT BACK OUT AGAIN.
- MOV DX,PORT[SI] ;GET THE PORT ADDRESS OF THIS LINE
- ADD DX,INTID
- INT_CAN:
- IN AL,DX ;GET INTERUPT ID REGESTER
- TEST AL,1 ;IF HE HAS ANYTHING TO COMPLAINE
- JNZ INT_NONE ;ABOUT, READ THEM ALL AND IGNORE.
- ADD DX,LSTAT-INTID ;JUST TO MAKE UART HAPPY, READ THE
- IN AL,DX ;LINE STATUS AND
- ADD DX,MSTAT-LSTAT ;THE MODEM STATUS TO
- IN AL,DX ;"RESET INTERUPT CONTROL"
- ADD DX,RXBUF-MSTAT ;READING THE RECEIVER MIGHT
- IN AL,DX ;HELP ALSO.
- ADD DX,INTID-RXBUF ;POINT BACK AT INTERUPT ID,
- JMP INT_CAN ;AND DO THIS AGAIN.
- INT_NONE:
- ADD DX,LSTAT-INTID ;CALC ADDRESS OF LINE STATUS,
- IN AL,DX ;INPUT IT OR SOMETIMES IT DOESN'T WORK
-
- ADD DX,LCTRL-LSTAT ;CALC ADDRESS OF LINE CONTROL REG
- MOV AL,LINE[SI] ;GET THE DEFAULT LINE
- OR AL,DLAB ;SET THE DIVISOR LATCH BIT
- OUT DX,AL ;SET UP DEFAULT LINE CHARS
- SUB DX,LCTRL ;POINT BACK AT FIRST PORT
- MOV AX,BAUD[SI] ;GET DIVISOR VALUE FOR BAUD RATE
- OUT DX,AL ;SEND LOW BYTE
- INC DX ;INC TO HIGH BYTE PORT
- MOV AL,AH ;GET HIGH BYTE,
- OUT DX,AL ;AND SEND TO BOARD.
- ADD DX,LCTRL-1 ;POINT AT LINE CONTROL AGAIN,
- MOV AL,LINE[SI] ;GET DEFAULT LINE CONTROL BITS AGAIN
- OUT DX,AL ;SET THEM WITHOUT DLAB ON.
- MOV LINE[SI],0 ;RE-USE LINE OFFSET AS STATUS
- SUB DX,LCTRL-INTEN ;POINT DX AT INTERUPT ENABLE PORT
- MOV AL,ALLINT ;SET UP TO GET ALL POSSIBLE INTS
- OUT DX,AL ;IN THE INTEN REGESTER.
- ADD DX,MCTRL-INTEN ;POINT AT MODEM STATUS REGESTER
- MOV AL,MODEM[SI] ;GET THE DEFAULT MODEM STATUS BITS,
- OUT DX,AL ;AND SET THEM IN MCTRL.
- MOV MODEM[SI],0 ;RE-USE THIS BYTE FOR INPUT STATUS.
- TEST INSPEC[SI],INXON ;IS INPUT THROTTLED WITH XON?
- JE DONE_INIT ;NO, LEAVE HIM BE.
- MOV AL,'Q' AND 01FH ;YES, SEND A CONTROL-Q
- MOV DX,PORT[SI] ;TO THE DEVICE AT INIT TIME,
- OUT DX,AL ;TO MAKE SURE IT WAKES UP.
- DONE_INIT:
- MOV AX,0 ;RETURN NO ERRORS.
- JMP EXIT
-
- DRIVER ENDS
- END
-